package cn.xyz.mianshi.service.impl;

import cn.xyz.commons.constants.KConstants;
import cn.xyz.commons.ex.ServiceException;
import cn.xyz.commons.support.Callback;
import cn.xyz.commons.support.mongo.MongoOperator;
import cn.xyz.commons.utils.*;
import cn.xyz.commons.vo.JSONMessage;
import cn.xyz.mianshi.model.PageResult;
import cn.xyz.mianshi.model.PageVO;
import cn.xyz.mianshi.service.FriendsManager;
import cn.xyz.mianshi.utils.SKBeanUtils;
import cn.xyz.mianshi.vo.AuthKeys;
import cn.xyz.mianshi.vo.Friends;
import cn.xyz.mianshi.vo.OfflineOperation;
import cn.xyz.mianshi.vo.User;
import cn.xyz.repository.mongo.FriendsRepositoryImpl;
import cn.xyz.repository.mongo.MongoRepository;
import cn.xyz.service.KXMPPServiceImpl;
import cn.xyz.service.KXMPPServiceImpl.MessageBean;
import cn.xyz.service.RedisServiceImpl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.mongodb.*;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.MongoIterable;
import com.mongodb.client.model.FindOneAndUpdateOptions;
import com.mongodb.client.model.ReturnDocument;
import org.apache.poi.ss.usermodel.Workbook;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.mongodb.morphia.Datastore;
import org.mongodb.morphia.query.Query;
import org.mongodb.morphia.query.UpdateOperations;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
public class FriendsManagerImpl extends MongoRepository<Friends, ObjectId> implements FriendsManager  {

	private static final String groupCode = "110";

	private static Logger Log = LoggerFactory.getLogger(FriendsManager.class);

	private static final String NEWFIREND = "shiku_newFirend";

	public static final String FANSDBNAME="u_fans";

	public static final String FRIENDSDBNAME="u_friends";

	private MongoDatabase friendsDB;

	@Autowired
	private AuthKeysServiceImpl authKeysService;



	@Override
	public Datastore getDatastore() {
		return SKBeanUtils.getDatastore();
	}

	@Override
	public Class<Friends> getEntityClass() {
		return Friends.class;
	}

	@Override
	public String getCollectionName(int userId) {
		int remainder=0;
		if(userId>KConstants.MIN_USERID) {
			remainder=(userId/KConstants.DB_REMAINDER.ADDRESSBOOK);
		}
		return String.valueOf(remainder);
	}

	public String getFansCollectionName(int userId) {
		int remainder=0;
		if(userId>KConstants.MIN_USERID) {
			remainder=(userId/KConstants.DB_REMAINDER.ADDRESSBOOK);
		}
		return String.valueOf(remainder);
	}
	public String getNewFriendCollectionName(int userId) {
		int remainder=0;
		if(userId>KConstants.MIN_USERID) {
			remainder=(userId/KConstants.DB_REMAINDER.ADDRESSBOOK);
		}
		return String.valueOf(remainder);
	}
	public MongoCollection<Document> getNewFriendCollection(int userId) {
		String collectionName = getNewFriendCollectionName(userId);
		MongoDatabase database = SKBeanUtils.getLocalSpringBeanManager().getMongoClient().getDatabase(NEWFIREND);
		return database.getCollection(collectionName);
	}



	public long getFriendCount(){
		long count=0;
		MongoIterable<String> listCollectionNames = friendsDB.listCollectionNames();
		for (String string : listCollectionNames) {
			count+=friendsDB.getCollection(string).count();
		}
		return count;
	}
	@Override
	public MongoCollection<DBObject> getDBObjectCollection(int userId) {
		String collectionName = getCollectionName(userId);
		if(null==friendsDB) {
			friendsDB=SKBeanUtils.getLocalSpringBeanManager().getMongoClient().getDatabase(FRIENDSDBNAME);
		}
		return friendsDB.getCollection(collectionName,DBObject.class);
	}

	public MongoCollection<Document> getCollection(int userId) {
		String collectionName = getCollectionName(userId);
		if(null==friendsDB) {
			friendsDB=SKBeanUtils.getLocalSpringBeanManager().getMongoClient().getDatabase(FRIENDSDBNAME);
		}
		return friendsDB.getCollection(collectionName);
	}

	/** Fans Collection
	 * @param userId
	 * @return
	 */
	/** Friends Collection
	 * @param userId
	 * @return
	 */
	public MongoCollection<DBObject> getFriendsMongoCollection(int userId){
		return getDBObjectCollection(userId);
	}



	private static FriendsRepositoryImpl getFriendsRepository(){
		FriendsRepositoryImpl getFriendsRepository = SKBeanUtils.getFriendsRepository();
		return getFriendsRepository;
	}

	private static UserManagerImpl getUserManager(){
		UserManagerImpl userManager = SKBeanUtils.getUserManager();
		return userManager;
	};
	
	/**
	 * @return
	 */
	private RedisServiceImpl getRedisServiceImpl() {
		// TODO Auto-generated method stub
		return SKBeanUtils.getRedisService();
	}

	@Override
	public Friends addBlacklist(Integer userId, Integer toUserId) {
		// 是否存在AB关系
		Friends friendsAB = getFriendsRepository().getFriends(userId, toUserId);
		Friends friendsBA= getFriendsRepository().getFriends(toUserId, userId);

		if (null == friendsAB) {
			Friends friends = new Friends(userId, toUserId,getUserManager().getNickName(toUserId), Friends.Status.Stranger, Friends.Blacklist.Yes,0);
			getFriendsRepository().saveFriends(friends);
		} else {
			// 更新关系
			getFriendsRepository().updateFriends(new Friends(userId, toUserId,null, -1, Friends.Blacklist.Yes,(0 == friendsAB.getIsBeenBlack())?0:friendsAB.getIsBeenBlack()));
			getFriendsRepository().updateFriends(new Friends(toUserId, userId,null, null, (0 == friendsBA.getBlacklist()?Friends.Blacklist.No:friendsBA.getBlacklist()),1));
		}
		SKBeanUtils.getTigaseManager().deleteLastMsg(userId, toUserId.toString());
		//SKBeanUtils.getTigaseManager().deleteLastMsg(toUserId.toString(),userId.toString());
		// 维护好友数据
		deleteFriendsInfo(userId, toUserId);
		// 更新好友设置操作时间
		updateOfflineOperation(userId, toUserId);
		return getFriendsRepository().getFriends(userId, toUserId);
	}

	/** @Description: 维护用户通讯录好友缓存
	* @param userId
	* @param toUserId
	**/
	private void deleteAddressFriendsInfo(Integer userId,Integer toUserId){
		// 通讯录好友id
		getRedisServiceImpl().delAddressBookFriendsUserIds(userId);
		getRedisServiceImpl().delAddressBookFriendsUserIds(toUserId);
		deleteFriendsInfo(userId, toUserId);
	}

	/** @Description: 维护用户好友缓存
	* @param userId
	* @param toUserId
	**/ 
	private void deleteFriendsInfo(Integer userId,Integer toUserId){
		// 好友userIdsList
		getRedisServiceImpl().deleteFriendsUserIdsList(userId);
		getRedisServiceImpl().deleteFriendsUserIdsList(toUserId);
		// 好友列表
		getRedisServiceImpl().deleteFriends(userId);
		getRedisServiceImpl().deleteFriends(toUserId);
	}
	
	// 后台加入黑名单（后台可以互相拉黑）
	public Friends consoleAddBlacklist(Integer userId, Integer toUserId,int adminUserId) {
		// 是否存在AB关系
		Friends friendsAB = getFriendsRepository().getFriends(userId, toUserId);
		Friends friendsBA= getFriendsRepository().getFriends(toUserId, userId);
		if (null == friendsAB) {
			Friends friends = new Friends(userId, toUserId,getUserManager().getNickName(toUserId), Friends.Status.Stranger, Friends.Blacklist.Yes,0);
			getFriendsRepository().saveFriends(friends);
		} else {
			// 更新关系
			getFriendsRepository().updateFriends(new Friends(userId, toUserId,null, -1, Friends.Blacklist.Yes,(0 == friendsAB.getIsBeenBlack())?0:friendsAB.getIsBeenBlack()));
			getFriendsRepository().updateFriends(new Friends(toUserId, userId,null, null, (0 == friendsBA.getBlacklist()?Friends.Blacklist.No:friendsBA.getBlacklist()),1));
		}
		SKBeanUtils.getTigaseManager().deleteLastMsg(userId, toUserId.toString());
		ThreadUtil.executeInThread(new Callback() {
			
			@Override
			public void execute(Object obj) {

				//xmpp推送消息
				MessageBean messageBean=new MessageBean();
				messageBean.setType(KXMPPServiceImpl.joinBlacklist);
				messageBean.setFromUserId("10005");
				messageBean.setFromUserName("后台系统管理员");
				MessageBean beanVo = new MessageBean();
				beanVo.setFromUserId(userId+"");
				beanVo.setFromUserName(getUserManager().getNickName(userId));
				beanVo.setToUserId(toUserId+"");
				beanVo.setToUserName(getUserManager().getNickName(toUserId));
				messageBean.setObjectId(JSONObject.toJSONString(beanVo));
				messageBean.setMessageId(StringUtil.randomUUID());
				try {
					List<Integer> userIdlist = new ArrayList<Integer>();
					userIdlist.add(userId);
					userIdlist.add(toUserId);
					KXMPPServiceImpl.getInstance().send(messageBean,userIdlist);
				} catch (Exception e) {
				}
			
			}
		});
		// 维护好友数据
		deleteFriendsInfo(userId, toUserId);
		// 更新好友设置操作时间
		updateOfflineOperation(userId, toUserId);
		return getFriendsRepository().getFriends(userId, toUserId);
	}
	
	
	
	
	public void updateFriends(Friends friends){
		 getFriendsRepository().updateFriends(friends);
	}
	public void updateFriendsNickName(int userId,String nickName) {
		MongoDatabase database = SKBeanUtils.getLocalSpringBeanManager().getMongoClient().getDatabase(getCollectionName());
		MongoIterable<String> listCollectionNames = database.listCollectionNames();
		Document query=new Document();
		query.append("toUserId",userId);
		Document update=new Document(MongoOperator.SET,new Document("toNickname", nickName));
		MongoCollection<Document> collection=null;
		for (String string : listCollectionNames) {
			collection = database.getCollection(string);
			collection.updateMany(query, update);
		}

	}
	public boolean isBlack(Integer toUserId) {
		Friends friends = getFriends(ReqUtil.getUserId(), toUserId);
		if (friends == null)
			return false;
		return friends.getStatus() == -1 ? true : false;
	}
	
	public boolean isBlack(Integer userId,Integer toUserId) {
		Friends friends = getFriends(userId, toUserId);
		if (friends == null)
			return false;
		return friends.getStatus() == -1 ? true : false;
	}

	private void saveFansCount(int userId) {
		BasicDBObject q = new BasicDBObject("_id", userId);
		DBCollection dbCollection = SKBeanUtils.getTigaseDatastore().getDB().getCollection("shiku_msgs_count");
		if (0 == dbCollection.count(q)) {
			BasicDBObject jo = new BasicDBObject("_id", userId);
			jo.put("count", 0);// 消息数
			jo.put("fansCount", 1);// 粉丝数
			dbCollection.insert(jo);
		} else {
			dbCollection.update(q, new BasicDBObject("$inc", new BasicDBObject("fansCount", 1)));
		}
	}

	@Override
	public boolean addFriends(Integer userId, Integer toUserId) {

		int toUserType = 0;
		List<Integer> toUserRoles = SKBeanUtils.getRoleManager().getUserRoles(toUserId);
		if (toUserRoles.size() > 0 && null != toUserRoles) {
			if (toUserRoles.contains(2))
				toUserType = 2;
		}
		int userType = 0;
		List<Integer> userRoles = SKBeanUtils.getRoleManager().getUserRoles(userId);
		if (userRoles.size() > 0 && null != userRoles) {
			if (userRoles.contains(2))
				userType = 2;
		}
		Friends friends = getFriends(userId, toUserId);
		if (null == friends) {
			getFriendsRepository().saveFriends(new Friends(userId, toUserId, getUserManager().getNickName(toUserId),
					Friends.Status.Friends, 0, 0, toUserRoles, toUserType, 4));
			saveFansCount(toUserId);
		} else {
			saveFansCount(toUserId);
			friends.setStatus(Friends.Status.Friends);
			friends.setToUserType(toUserType);
			friends.setToFriendsRole(userRoles);
			updateFriends(friends);
		}
		Friends toFriends = getFriends(toUserId, userId);
		if (null == toFriends) {
			getFriendsRepository().saveFriends(new Friends(toUserId, userId, getUserManager().getNickName(userId),
					Friends.Status.Friends, 0, 0, userRoles, userType, 4));
			saveFansCount(toUserId);
		} else {
			saveFansCount(toUserId);
			updateFriends(new Friends(userId, toUserId,getUserManager().getNickName(toUserId), Friends.Status.Friends,0,0,toUserRoles,toUserType,4));
			updateFriends(new Friends(toUserId, userId,getUserManager().getNickName(userId),Friends.Status.Friends,0,0,userRoles,userType,4));
		}
		deleteFriendsInfo(userId, toUserId);
		return true;
	}
	
	@Override
	public Friends deleteBlacklist(Integer userId, Integer toUserId) {
		// 是否存在AB关系
		Friends friendsAB = getFriendsRepository().getFriends(userId, toUserId);
		Friends friendsBA = getFriendsRepository().getFriends(toUserId, userId);

		if (null != friendsAB) {
            // 陌生人黑名单
            if (Friends.Blacklist.Yes == friendsAB.getBlacklist() && Friends.Status.Stranger == friendsAB.getStatus()) {
                // 物理删除
                getFriendsRepository().deleteFriends(userId, toUserId);
            } else {
                // 恢复关系
                getFriendsRepository().updateFriends(new Friends(userId, toUserId,null, 2, Friends.Blacklist.No,(friendsAB.getIsBeenBlack())));
                getFriendsRepository().updateFriends(new Friends(toUserId, userId,null, (friendsBA.getStatus()), (0 == friendsBA.getBlacklist()?Friends.Blacklist.No:friendsBA.getBlacklist()),0));
            }
            // 是否存在AB关系
            friendsAB = getFriendsRepository().getFriends(userId, toUserId);
            // 维护好友数据
            deleteFriendsInfo(userId, toUserId);
            // 更新好友设置操作时间
            updateOfflineOperation(userId, toUserId);
		}
		return friendsAB;
	}

	/** @Description:（后台移除黑名单） 
	* @param userId
	* @param toUserId
	* @return
	**/ 
	public Friends consoleDeleteBlacklist(Integer userId, Integer toUserId,int adminUserId) {
		// 是否存在AB关系
		Friends friendsAB = getFriendsRepository().getFriends(userId, toUserId);
		Friends friendsBA = getFriendsRepository().getFriends(toUserId, userId);

		if (null == friendsAB) {
			// 无记录
		} else {
			// 陌生人黑名单
			if (Friends.Blacklist.Yes == friendsAB.getBlacklist() && Friends.Status.Stranger == friendsAB.getStatus()) {
				// 物理删除
				getFriendsRepository().deleteFriends(userId, toUserId);
			} else {
				// 恢复关系
				getFriendsRepository().updateFriends(new Friends(userId, toUserId,null, 2, Friends.Blacklist.No,(0 == friendsAB.getIsBeenBlack()?0:friendsAB.getIsBeenBlack())));
				getFriendsRepository().updateFriends(new Friends(toUserId, userId,null, (2 == friendsBA.getStatus()?2:friendsBA.getStatus()), (0 == friendsBA.getBlacklist()?Friends.Blacklist.No:friendsBA.getBlacklist()),0));
			}
			// 是否存在AB关系
			friendsAB = getFriendsRepository().getFriends(userId, toUserId);
		}
		
		ThreadUtil.executeInThread(new Callback() {
			
			@Override
			public void execute(Object obj) {

				//xmpp推送消息
				MessageBean messageBean=new MessageBean();
				messageBean.setType(KXMPPServiceImpl.moveBlacklist);
				messageBean.setFromUserId(adminUserId+"");
				messageBean.setFromUserName("后台系统管理员");
				MessageBean beanVo = new MessageBean();
				beanVo.setFromUserId(userId+"");
				beanVo.setFromUserName(getUserManager().getNickName(userId));
				beanVo.setToUserId(toUserId+"");
				beanVo.setToUserName(getUserManager().getNickName(toUserId));
				messageBean.setObjectId(JSONObject.toJSONString(beanVo));
				messageBean.setMessageId(StringUtil.randomUUID());
				try {
					List<Integer> userIdlist = new ArrayList<Integer>();
					userIdlist.add(userId);
					userIdlist.add(toUserId);
					KXMPPServiceImpl.getInstance().send(messageBean,userIdlist);
				} catch (Exception e) {
				}
			}
		});
		// 维护好友数据
		deleteFriendsInfo(userId, toUserId);
		return friendsAB;
	}
	
	@Override
	public boolean deleteFriends(Integer userId, Integer toUserId) {
		getFriendsRepository().deleteFriends(userId, toUserId);
		getFriendsRepository().deleteFriends(toUserId, userId);
		SKBeanUtils.getTigaseManager().deleteLastMsg(userId, toUserId.toString());
		SKBeanUtils.getTigaseManager().deleteLastMsg(toUserId,userId.toString());

		/**
		 * 维护好友标签数据
		 */
		SKBeanUtils.getFriendGroupManager().deleteFriendToFriendGroup(userId,toUserId);
		// 维护好友数据
		deleteFriendsInfo(userId, toUserId);
		// 更新好友设置操作时间
		updateOfflineOperation(userId, toUserId);
		return true;
	}
	
	/** @Description:（后台删除好友-xmpp发通知） 
	* @return
	**/
	public boolean consoleDeleteFriends(Integer userId, Integer adminUserId, String... toUserIds) {
		for(String strtoUserId : toUserIds){
			Integer toUserId = Integer.valueOf(strtoUserId);
			getFriendsRepository().deleteFriends(userId, toUserId);
			getFriendsRepository().deleteFriends(toUserId, userId);
			SKBeanUtils.getTigaseManager().deleteLastMsg(userId, toUserId.toString());
			SKBeanUtils.getTigaseManager().deleteLastMsg(toUserId,userId.toString());
			ThreadUtil.executeInThread(new Callback() {
				
				@Override
				public void execute(Object obj) {
					//以系统号发送删除好友通知
					MessageBean messageBean=new MessageBean();
					messageBean.setType(KXMPPServiceImpl.deleteFriends);
					messageBean.setFromUserId(adminUserId+"");
					messageBean.setFromUserName("后台系统管理员");
					MessageBean beanVo = new MessageBean();
					beanVo.setFromUserId(userId+"");
					beanVo.setFromUserName(getUserManager().getNickName(userId));
					beanVo.setToUserId(toUserId+"");
					beanVo.setToUserName(getUserManager().getNickName(toUserId));
					messageBean.setObjectId(JSONObject.toJSONString(beanVo));
					messageBean.setMessageId(StringUtil.randomUUID());
					messageBean.setContent("系统解除了你们好友关系");
					messageBean.setMessageId(StringUtil.randomUUID());
					try {
						List<Integer> userIdlist = new ArrayList<Integer>();
						userIdlist.add(userId);
						userIdlist.add(toUserId);
						KXMPPServiceImpl.getInstance().send(messageBean,userIdlist);
					} catch (Exception e) {
					}
					// 维护好友缓存
					deleteFriendsInfo(userId, toUserId);
				}
			});
		}		
		return true;
	}
	

	@SuppressWarnings("unused")
	@Override
	public JSONMessage followUser(Integer userId, Integer toUserId,Integer fromAddType) {
		final String serviceCode = "08";
		JSONMessage jMessage = null;
		User toUser = getUserManager().getUser(toUserId);

		List<Integer> toUserRoles = SKBeanUtils.getRoleManager().getUserRoles(toUserId);
		//好友不存在
		if(null==toUser){
			if(10000==toUserId)
				return null;
			else
				return JSONMessage.failureByErrCode(KConstants.ResultCode.UserNotExist);

		}
		int toUserType =toUser.getUserType();
		try {
			User user = getUserManager().getUser(userId);
			int userType = 0;
			List<Integer> userRoles = SKBeanUtils.getRoleManager().getUserRoles(userId);
			if(userRoles.size()>0 && null != userRoles){
				if(userRoles.contains(2))
					userType = 2;
			}

			// 是否存在AB关系
			Friends friendsAB = getFriendsRepository().getFriends(userId, toUserId);
			// 是否存在BA关系
			Friends friendsBA = getFriendsRepository().getFriends(toUserId, userId);
			// 获取目标用户设置
			User.UserSettings userSettingsB = getUserManager().getSettings(toUserId);

			// ----------------------------
			// 0 0 0 0 无记录 执行关注逻辑
			// A B 1 0 非正常 执行关注逻辑
			// A B 1 1 拉黑陌生人 执行关注逻辑
			// A B 2 0 关注 重复关注
			// A B 3 0 好友 重复关注
			// A B 2 1 拉黑关注 恢复关系
			// A B 3 1 拉黑好友 恢复关系
			// ----------------------------
			// 无AB关系或陌生人黑名单关系，加关注
			if(null != friendsAB&&friendsAB.getIsBeenBlack()==1){
				return jMessage = JSONMessage.failureByErrCode(KConstants.ResultCode.AddFriendsFailure);
			}
			if (null == friendsAB || Friends.Status.Stranger == friendsAB.getStatus()) {
				// 目标用户拒绝关注
				if (0 == userSettingsB.getAllowAtt()) {
					jMessage = new JSONMessage(groupCode, serviceCode, "01", "关注失败，目标用户拒绝关注");
				}
				// 目标用户允许关注
				else {
					int statusA = 0;

					// 目标用户加好需验证，执行加关注。过滤公众号开启好友验证
					if (1 == userSettingsB.getFriendsVerify() && 2 != toUserType) {
						// ----------------------------
						// 0 0 0 0 无记录 执行单向关注
						// B A 1 0 非正常 执行单向关注
						// B A 1 1 拉黑陌生人 执行单向关注
						// B A 2 0 关注 加好友
						// B A 3 0 好友 加好友
						// B A 2 1 拉黑关注 加好友
						// B A 3 1 拉黑好友 加好友
						// ----------------------------
						// 无BA关系或陌生人黑名单关系，单向关注
						if (null == friendsBA || Friends.Status.Stranger == friendsBA.getStatus()) {
							statusA = Friends.Status.Attention;
						} else {
							statusA = Friends.Status.Friends;

							getFriendsRepository()
									.updateFriends(new Friends(toUserId, user.getUserId(),user.getNickname(), Friends.Status.Friends));
						}
					}
					// 目标用户加好友无需验证，执行加好友
					else {
						statusA = Friends.Status.Friends;

						if (null == friendsBA) {
							getFriendsRepository().saveFriends(new Friends(toUserId, user.getUserId(),user.getNickname(),
									Friends.Status.Friends, Friends.Blacklist.No,0,userRoles,userType,fromAddType));

							saveFansCount(toUserId);
						} else
							getFriendsRepository()
									.updateFriends(new Friends(toUserId, user.getUserId(),user.getNickname(), Friends.Status.Friends,userType,userRoles));//改变usertype
					}

					if (null == friendsAB) {
						getFriendsRepository().saveFriends(new Friends(userId, toUserId,toUser.getNickname(), statusA, Friends.Blacklist.No,0,toUserRoles,toUserType,fromAddType));
						saveFansCount(toUserId);
					} else {
						getFriendsRepository().updateFriends(new Friends(userId, toUserId,toUser.getNickname(), statusA, Friends.Blacklist.No,0));
					}

					if (statusA == Friends.Status.Attention) {
						HashMap<String, Object> newMap = MapUtil.newMap("type", 1);
						newMap.put("fromAddType", fromAddType);
						jMessage = JSONMessage.success(KConstants.ResultCode.AttentionSuccess, newMap);
					} else {
						HashMap<String, Object> newMap = MapUtil.newMap("type", 2);
						newMap.put("fromAddType", fromAddType);
						jMessage = JSONMessage.success(KConstants.ResultCode.AttentionSuccessAndFriends,newMap);
					}

				}
			}
			// 有关注或好友关系，重复关注
			else if (Friends.Blacklist.No == friendsAB.getBlacklist()) {
				if (Friends.Status.Attention == friendsAB.getStatus()) {
					// 开启好友验证后关闭
					if(0 == userSettingsB.getFriendsVerify()){
						Integer statusA = Friends.Status.Friends;
						if (null == friendsBA) {
							getFriendsRepository().saveFriends(new Friends(toUserId, user.getUserId(),user.getNickname(),Friends.Status.Friends, Friends.Blacklist.No,0,userRoles,userType,fromAddType));
							saveFansCount(toUserId);
						} else{
							getFriendsRepository().updateFriends(new Friends(toUserId, user.getUserId(),user.getNickname(), Friends.Status.Friends));
						}
						if (null == friendsAB) {
							getFriendsRepository().saveFriends(new Friends(userId, toUserId,toUser.getNickname(), statusA, Friends.Blacklist.No,0,toUserRoles,toUserType,fromAddType));
							saveFansCount(toUserId);
						} else {
							getFriendsRepository().updateFriends(new Friends(userId, toUserId,toUser.getNickname(), statusA, Friends.Blacklist.No,0));
						}
						HashMap<String, Object> newMap = MapUtil.newMap("type", 2);
						newMap.put("fromAddType", fromAddType);
						jMessage = JSONMessage.success(KConstants.ResultCode.AttentionSuccessAndFriends, newMap);
					}else if(1 == userSettingsB.getFriendsVerify()){
						HashMap<String, Object> newMap = MapUtil.newMap("type", 1);
						newMap.put("fromAddType", fromAddType);
						jMessage = JSONMessage.success(KConstants.ResultCode.AttentionSuccess, newMap);
					}
				} else {
					HashMap<String, Object> newMap = MapUtil.newMap("type", 2);
					newMap.put("fromAddType", fromAddType);
					jMessage = JSONMessage.success(KConstants.ResultCode.AttentionSuccessAndFriends,newMap);
				}
			}
			// 有关注黑名单或好友黑名单关系，恢复关系
			else {
				getFriendsRepository().updateFriends(new Friends(userId, toUserId,toUser.getNickname(), Friends.Blacklist.No));

				jMessage = null;
			}
			// 维护好友数据
			deleteFriendsInfo(userId, toUserId);
			// 更新好友设置操作时间
			updateOfflineOperation(userId, toUserId);
		} catch (Exception e) {
			Log.error("关注失败", e);
			jMessage = JSONMessage.failureByErrCode(KConstants.ResultCode.AttentionFailure);
		}
		return jMessage;
	}
	
	/** @Description:更新好友设置操作时间
	* @param userId
	* @param toUserId
	**/
	public void updateOfflineOperation(Integer userId,Integer toUserId){
		Query<OfflineOperation> query = getDatastore().createQuery(OfflineOperation.class).field("userId").equal(userId).field("tag").equal(KConstants.MultipointLogin.TAG_FRIEND).field("friendId").equal(String.valueOf(toUserId));
		if(null == query.get()){
			getDatastore().save(new OfflineOperation(userId, KConstants.MultipointLogin.TAG_FRIEND, String.valueOf(toUserId), DateUtil.currentTimeSeconds()));
		}else{
			UpdateOperations<OfflineOperation> ops = getDatastore().createUpdateOperations(OfflineOperation.class);
			ops.set("operationTime", DateUtil.currentTimeSeconds());
			getDatastore().update(query, ops);
		}
	}

	// 批量添加好友
	@Override
	public JSONMessage batchFollowUser(Integer userId, String toUserIds) {
		JSONMessage jMessage = null;
		if(StringUtil.isEmpty(toUserIds))
			return null;
		int[] toUserId = StringUtil.getIntArray(toUserIds, ",");
		for(int i = 0; i < toUserId.length; i++){
			//好友不存在
			if(userId==toUserId[i]||10000==toUserId[i])
				continue;
			User toUser = getUserManager().getUser(toUserId[i]);
			if(null==toUser)
				continue;
			List<Integer> toUserRoles = SKBeanUtils.getRoleManager().getUserRoles(toUserId[i]);
			int toUserType =toUser.getUserType();
			try {
				User user = getUserManager().getUser(userId);
				int userType = 0;
				List<Integer> userRoles = SKBeanUtils.getRoleManager().getUserRoles(userId);
				if(userRoles.size()>0 && null != userRoles){
					if(userRoles.contains(2))
						userType = 2;
				}

				// 是否存在AB关系
				Friends friendsAB = getFriendsRepository().getFriends(userId, toUserId[i]);
				// 是否存在BA关系
				Friends friendsBA = getFriendsRepository().getFriends(toUserId[i], userId);
				// 获取目标用户设置
				User.UserSettings userSettingsB = getUserManager().getSettings(toUserId[i]);

				if(null != friendsAB&&friendsAB.getIsBeenBlack()==1){
//					return jMessage = JSONMessage.failure("加好友失败");
//					continue;
					throw new ServiceException(KConstants.ResultCode.WasAddBlacklist);
				}
				if (null == friendsAB || Friends.Status.Stranger == friendsAB.getStatus()) {
					// 目标用户拒绝关注
					if (0 == userSettingsB.getAllowAtt()) {
//						jMessage = new JSONMessage(groupCode, serviceCode, "01", "关注失败，目标用户拒绝关注");
						continue;
					}
					// 目标用户允许关注
					else {
						int statusA = 0;
							statusA = Friends.Status.Friends;

							if (null == friendsBA) {
								getFriendsRepository().saveFriends(new Friends(toUserId[i], user.getUserId(),user.getNickname(),
										Friends.Status.Friends, Friends.Blacklist.No,0,userRoles,userType,4));

								saveFansCount(toUserId[i]);
							} else
								getFriendsRepository()
										.updateFriends(new Friends(toUserId[i], user.getUserId(),user.getNickname(), Friends.Status.Friends));

						if (null == friendsAB) {
							getFriendsRepository().saveFriends(new Friends(userId, toUserId[i],toUser.getNickname(), statusA, Friends.Blacklist.No,0,toUserRoles,toUserType,4));
							saveFansCount(toUserId[i]);
						} else {
							getFriendsRepository().updateFriends(new Friends(userId, toUserId[i],toUser.getNickname(), statusA, Friends.Blacklist.No,0));
						}

					}
				}
				// 有关注或好友关系，重复关注
				else if (Friends.Blacklist.No == friendsAB.getBlacklist()) {
					if (Friends.Status.Attention == friendsAB.getStatus()){
						// 已关注的修改为好友状态
						getFriendsRepository().updateFriends(new Friends(userId, toUserId[i],toUser.getNickname(), Friends.Status.Friends,toUserType,toUserRoles));
						// 添加成为好友
						getFriendsRepository().saveFriends(new Friends(toUserId[i], user.getUserId(),user.getNickname(),
								Friends.Status.Friends, Friends.Blacklist.No,0,userRoles,"",userType));
//						continue;
					}
				}else {
					// 有关注黑名单或好友黑名单关系，恢复关系
					getFriendsRepository().updateFriends(new Friends(userId, toUserId[i],toUser.getNickname(), Friends.Blacklist.No));
					jMessage = null;
				}
				notify(userId, toUserId[i]);
				jMessage = JSONMessage.success();
				// 维护好友数据
				deleteAddressFriendsInfo(userId, toUserId[i]);
				// 更新好友设置操作时间
				updateOfflineOperation(userId, toUserId[i]);
			} catch (Exception e) {
				Log.error("通讯录添加好友失败", e.getMessage());
				jMessage = JSONMessage.failureByException(e);
			}
		}
		return jMessage;
	}
	
	
	/** @Description:（通讯录自动添加好友） 
	* @param userId
	* @param addressBook<userid 用户id, toRemark 备注 >
	* @return
	**/ 
	public JSONMessage autofollowUser(Integer userId, Map<String, String> addressBook) {
		final String serviceCode = "08";
		Integer toUserId  = Integer.valueOf(addressBook.get("toUserId"));
		String toRemark = addressBook.get("toRemark");

//		final String serviceCode = "08";
		JSONMessage jMessage = null;
			User toUser = getUserManager().getUser(toUserId);
			if(null==toUser)
				return null;
			int toUserType =toUser.getUserType();
			List<Integer> toUserRoles = SKBeanUtils.getRoleManager().getUserRoles(toUserId);
			//好友不存在
			if(10000==toUser.getUserId())
				return null;
			try {
				User user = getUserManager().getUser(userId);
				int userType = 0;
				List<Integer> userRoles = SKBeanUtils.getRoleManager().getUserRoles(userId);
				if(userRoles.size()>0 && null != userRoles){
					if(userRoles.contains(2))
						userType = 2;
				}

				// 是否存在AB关系
				Friends friendsAB = getFriendsRepository().getFriends(userId, toUserId);
				// 是否存在BA关系
				Friends friendsBA = getFriendsRepository().getFriends(toUserId, userId);
				// 获取目标用户设置
				User.UserSettings userSettingsB = getUserManager().getSettings(toUserId);

				if(null != friendsAB&&friendsAB.getIsBeenBlack()==1){
					return jMessage = JSONMessage.failureByErrCode(KConstants.ResultCode.AddFriendsFailure);
				}
				if (null == friendsAB || Friends.Status.Stranger == friendsAB.getStatus()) {
					// 目标用户拒绝关注
					if (0 == userSettingsB.getAllowAtt()) {
						jMessage = JSONMessage.failureByErrCode(KConstants.ResultCode.AttentionFailure);
					}
					// 目标用户允许关注
					else {
						int statusA = 0;
						// 目标用户加好友无需验证，执行加好友
//						else {
							statusA = Friends.Status.Friends;

							if (null == friendsBA) {
								getFriendsRepository().saveFriends(new Friends(toUserId, user.getUserId(),user.getNickname(),
										Friends.Status.Friends, Friends.Blacklist.No,0,userRoles,"",userType));

								saveFansCount(toUserId);
							} else
								getFriendsRepository()
										.updateFriends(new Friends(toUserId, user.getUserId(),user.getNickname(), Friends.Status.Friends));
//						}

						if (null == friendsAB) {
							getFriendsRepository().saveFriends(new Friends(userId, toUserId,toUser.getNickname(), statusA, Friends.Blacklist.No,0,toUserRoles,toRemark,toUserType));
							saveFansCount(toUserId);
						} else {
							getFriendsRepository().updateFriends(new Friends(userId, toUserId,toUser.getNickname(), statusA, Friends.Blacklist.No,0));
						}

					}
				}
				// 有关注或好友关系，重复关注
				else if (Friends.Blacklist.No == friendsAB.getBlacklist()) {
					if (Friends.Status.Attention == friendsAB.getStatus()){
						// 已关注的修改为好友状态
						getFriendsRepository().updateFriends(new Friends(userId, toUserId,toUser.getNickname(), Friends.Status.Friends,toUserType,toUserRoles));
						// 添加成为好友
						if(null==friendsBA) {
							getFriendsRepository().saveFriends(new Friends(toUserId, user.getUserId(), user.getNickname(),
									Friends.Status.Friends, Friends.Blacklist.No, 0, userRoles, "", userType));
						}else {
							getFriendsRepository().updateFriends(new Friends(toUserId, user.getUserId(),user.getNickname(),
									Friends.Status.Friends, Friends.Blacklist.No,0,userRoles,"",userType));
						}
					}
				}else {
					// 有关注黑名单或好友黑名单关系，恢复关系
					getFriendsRepository().updateFriends(new Friends(userId, toUserId,toUser.getNickname(), Friends.Blacklist.No));
					jMessage = null;
				}
				notify(userId, toUserId);
				// 维护好友数据
				deleteFriendsInfo(userId, toUserId);
				jMessage = JSONMessage.success();
			} catch (Exception e) {
				Log.error("关注失败", e);
				jMessage = JSONMessage.failureByErrCode(KConstants.ResultCode.AttentionFailure);
			}
		return jMessage;
	}
	
	public void notify(Integer userId,Integer toUserId){
		ThreadUtil.executeInThread(new Callback() {
			@Override
			public void execute(Object obj) {
					MessageBean messageBean=new MessageBean();
					messageBean.setType(KXMPPServiceImpl.batchAddFriend);
					messageBean.setFromUserId(String.valueOf(userId));
					messageBean.setFromUserName(SKBeanUtils.getUserManager().getNickName(userId));
					messageBean.setToUserId(String.valueOf(toUserId));
					messageBean.setToUserName(SKBeanUtils.getUserManager().getNickName(toUserId));
					messageBean.setContent(toUserId);
					messageBean.setMsgType(0);// 单聊消息
					messageBean.setMessageId(StringUtil.randomUUID());
					try {
						KXMPPServiceImpl.getInstance().send(messageBean);
					} catch (Exception e) {
						e.printStackTrace();
					}
			}
		});
	}
	
	public Friends getFriends(int userId, int toUserId) {
		return getFriendsRepository().getFriends(userId, toUserId);
	}
	
	public void getFriends(int userId, String... toUserIds) {
		for (String strToUserId : toUserIds) {
			Integer toUserId = Integer.valueOf(strToUserId);
			Friends friends = getFriendsRepository().getFriends(userId, toUserId);
			if(null == friends)
				throw new ServiceException(KConstants.ResultCode.NotYourFriends);
		
		}
	}
	
	public List<Friends> getFansList(Integer userId) {
		
		List<Friends> result =getEntityListsByKey("userId", userId);
		result.forEach(friends->{
		   User	user = getUserManager().getUser(friends.getToUserId());
		   if(null==user)
		   		return;
			friends.setToNickname(user.getNickname());
		});
		return result;
	}



	@Override
	public Friends getFriends(Friends p) {
		return getFriendsRepository().getFriends(p.getUserId(), p.getToUserId());
	}

	@Override
	public List<Integer> getFriendsIdList(int userId) {
		List<Integer> result = Lists.newArrayList();

		try {
			List<Friends> friendsList = getFriendsRepository().queryFriends(userId);
			friendsList.forEach(friends -> {
				result.add(friends.getToUserId());
			});
		} catch (Exception e) {
			e.printStackTrace();
		}

		return result;
	}

	@Override
	public List<Friends> queryBlacklist(Integer userId,int pageIndex,int pageSize) {
		return getFriendsRepository().queryBlacklist(userId,pageIndex,pageSize);
	}
	
	public PageVO queryBlacklistWeb(Integer userId,int pageIndex,int pageSize) {
		return getFriendsRepository().queryBlacklistWeb(userId,pageIndex,pageSize);
	}

	@Override
	public List<Integer> queryFansId(Integer userId) {
		return getFriendsRepository().queryFansId(userId);
	}
	/**
	 * 查询好友是否开启 免打扰
	 * @return
	 */
	public boolean getFriendIsNoPushMsg(Integer userId, Integer toUserId) {
		/**
		 * 分库分表下的friends数据
		 */
		MongoCursor<DBObject> iterator = getDBObjectCollection(userId).find(new Document("userId",userId).append("toUserId", toUserId).append("offlineNoPushMsg", 1)).iterator();
		DBObject dbObject = null;

		try {
			while(iterator.hasNext()){
				dbObject = iterator.next();
			}
		} finally {
			if(null!=iterator)
				iterator.close();
		}
		return null != dbObject;
	}
	@Override
	public List<Friends> queryFollow(Integer userId,int status) {
		List<Friends> userfriends = SKBeanUtils.getRedisService().getFriendsList(userId);
		if(null != userfriends && userfriends.size() > 0){
			return userfriends;
		}else{
			if(0 == status)
				status = 2;  //好友
			List<Friends> result = getFriendsRepository().queryFollow(userId,status);
			Iterator<Friends> iter = result.iterator();
			while (iter.hasNext()) { 
				Friends friends=iter.next();
				User user = getUserManager().getUser(friends.getToUserId());
				if(null==user){
					iter.remove();
					deleteFansAndFriends(friends.getToUserId());
					deleteFriends(userId,friends.getToUserId());
					continue;
				}
				AuthKeys authks = authKeysService.getAuthKeys(user.getUserId());
				if(authks!=null) {
					friends.setDhMsgPublicKey(authks.getMsgDHKeyPair()!=null ? authks.getMsgDHKeyPair().getPublicKey() : "");
					friends.setRsaMsgPublicKey(authks.getMsgRsaKeyPair()!=null ? authks.getMsgRsaKeyPair().getPublicKey() : "");
				}

				friends.setToNickname(user.getNickname());
			}
			SKBeanUtils.getRedisService().saveFriendsList(userId,result);
			return result;
		}
	}
	
	/** 后台管理好友列表
	 * @param userId
	 * @param toUserId
	 * @param status
	 * @param page
	 * @param limit
	 * @return
	 * @throws InvocationTargetException
	 * @throws IllegalAccessException
	 */
	public PageResult<Friends> consoleQueryFollow(Integer userId,Integer toUserId,int status,int page,int limit) throws IllegalAccessException, InvocationTargetException {
		PageResult<Friends> result = new PageResult<Friends>();
		result = getFriendsRepository().consoleQueryFollow(userId,toUserId,status,page,limit);
		Iterator<Friends> iter = result.getData().iterator(); 
		while (iter.hasNext()) { 
			Friends friends=iter.next();
			User user=null;
			try {
				 user = getUserManager().getUser(friends.getToUserId());
			}catch (Exception e){
				logger.error(e.getMessage());
				continue;
			}

			friends.setNickname(getUserManager().getNickName(userId));
			if(null==user){
				iter.remove();
				deleteFansAndFriends(friends.getToUserId());
				continue;
			}
			friends.setToNickname(user.getNickname());
		}
		return result;
	}

	@Override
	public List<Integer> queryFollowId(Integer userId) {
		return getFriendsRepository().queryFollowId(userId);
	}

	@Override
	public List<Friends> queryFriends(Integer userId) {
		List<Friends> result = getFriendsRepository().queryFriends(userId);

		for (Friends friends : result) {
			User toUser = getUserManager().getUser(friends.getToUserId());
			if(null==toUser){
				deleteFansAndFriends(friends.getToUserId());
				continue;
			}
			friends.setToNickname(toUser.getNickname());
			//friends.setCompanyId(toUser.getCompanyId());
		}

		return result;
	}
	
	
	@Override   //返回好友的userId 和单向关注的userId
	public List<Integer> friendsAndAttentionUserId(Integer userId,String type) {
		List<Friends> result = new ArrayList<Friends>();
		if("friendList".equals(type) || "blackList".equals(type)){  //返回好友的userId 和单向关注的userId
			 result = getFriendsRepository().friendsOrBlackList(userId, type);
		}else{
			throw new ServiceException(KConstants.ResultCode.ParamsAuthFail);
		}
		List<Integer> userIds = new ArrayList<Integer>();
		for (Friends friend : result) {
			userIds.add(friend.getToUserId());
		}
		return userIds;
	}

	@Override
	public PageVO queryFriends(Integer userId,int status,String keyword, int pageIndex, int pageSize) {
		/**
		 * 分库分表friends 数据
		 */
		Document document = new Document("userId",userId);
		if(0<status)
			document.append("status", status);
		if(!StringUtil.isEmpty(keyword)){
			Pattern pattern = Pattern.compile("^.*" + keyword +".*$", Pattern.CASE_INSENSITIVE);
	    	List<Document> documents = new ArrayList<Document>();
	    	documents.add(new Document("toNickname",pattern));
	    	documents.add(new Document("remarkName",pattern));
	    	document.append(MongoOperator.OR,documents);
		}
		MongoCollection<DBObject> friendsCollection = getFriendsMongoCollection(userId);
		long count = friendsCollection.count(document);
		List<Friends> friendList = new ArrayList<Friends>();
     	MongoCursor<DBObject> iterator = getFriendsMongoCollection(userId).find(document).skip(pageIndex*pageSize).limit(pageSize).iterator();
    	try {
    		while(iterator.hasNext()){
        		DBObject dbObject = iterator.next();
        		 try {
        			 Friends friends = DocumentToJavaBean.dbObject2Bean(dbObject, new Friends());
        			 if(null!=friends) {
						 AuthKeys authks = authKeysService.getAuthKeys(friends.getToUserId());
						 if(authks!=null) {
							 friends.setDhMsgPublicKey(authks.getMsgDHKeyPair()!=null ? authks.getMsgDHKeyPair().getPublicKey() : "");
							 friends.setRsaMsgPublicKey(authks.getMsgRsaKeyPair()!=null ? authks.getMsgRsaKeyPair().getPublicKey() : "");
						 }
						 friendList.add(friends);
					 }
    			} catch (Exception e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
        	}
		} finally {
			if(null!=iterator)
				iterator.close();
		}
    	PageVO pageVO = new PageVO(friendList, count, pageIndex, pageSize);
		return  pageVO;
	}
	public List<Friends> queryFriendsList(Integer userId,int status, int pageIndex, int pageSize) {
		/**
		 * 分库分表friends数据
		 */
		List<Friends> friendList = new ArrayList<Friends>();
		Document document = new Document("userId", userId);
		if(0 < status)
			document.append("status", status);
		MongoCursor<DBObject> iterator = getFriendsMongoCollection(userId).find(document).skip(pageIndex*pageSize).limit(pageSize).iterator();

		while(iterator.hasNext()){
			DBObject dbObject = iterator.next();
//			Friends friends = DocumentToJavaBean.dbObject2BeanByMorphia(morphia, getCollectionName(userId), Friends.class, dbObject);
			 try {
				 Friends friends = DocumentToJavaBean.dbObject2Bean(dbObject, new Friends());
				 friendList.add(friends);
			} catch (IllegalAccessException | InvocationTargetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return friendList;
	}

	
	
	/**
	 * 取消关注
	 */
	@Override
	public boolean unfollowUser(Integer userId, Integer toUserId) {
		// 删除用户关注
		getFriendsRepository().deleteFriends(userId, toUserId);
		// 更新好友设置操作时间
		updateOfflineOperation(userId, toUserId);
		return true;
	}

	@Override
	public Friends updateRemark(int userId, int toUserId, String remarkName,String describe) {
//		Friends friends = new Friends(userId, toUserId);
//		friends.setRemarkName(remarkName);
//		return getFriendsRepository().updateFriends(friends);
		return getFriendsRepository().updateFriendRemarkName(userId, toUserId, remarkName,describe);
	}



	@Override
	public void deleteFansAndFriends(int userId) {
		getFriendsRepository().deleteFriends(userId);
	}

	/* (non-Javadoc)
	 * @see cn.xyz.mianshi.service.FriendsManager#newFriendList(int,int,int)
	 */
	@Override
	public List<Document> newFriendList(int userId,int pageIndex,int pageSize) {
		MongoCollection<Document> collection = getNewFriendCollection(userId);
		List<Document> result= Lists.newArrayList();
		Document query=new Document("userId", String.valueOf(userId));
		MongoCursor<Document> cursor=collection.find(query)
		.sort(new Document("modifyTime", -1))
		.skip(pageIndex * pageSize).limit(pageSize).iterator();
		
			Friends friends=null;
			Document newFriends=null;
			Integer toUserId=0;
			
			try {
				while (cursor.hasNext()) {
					newFriends=cursor.next();
					 toUserId =Integer.valueOf(newFriends.getString("toUserId"));
					 friends=getFriends(Integer.valueOf(newFriends.getString("userId")),toUserId);
					 newFriends.put("toNickname", getUserManager().getNickName(toUserId));
					if(null!=friends)
						newFriends.put("status", friends.getStatus());
					result.add(newFriends);
				}
			} finally {
				if(null!=cursor)
					cursor.close();
			}
			return result;
		
	}
	
	@SuppressWarnings("deprecation")
	public PageVO newFriendListWeb(int userId,int pageIndex,int pageSize) {
		MongoCollection<Document> collection = getNewFriendCollection(userId);
		List<Document> result= Lists.newArrayList();
		Document query=new Document("userId", String.valueOf(userId));
		MongoCursor<Document> cursor=collection.find(query)
		.sort(new Document("modifyTime", -1))
		.skip(pageIndex * pageSize).limit(pageSize).iterator();

			Friends friends=null;
			Document newFriends=null;
			Integer toUserId=0;

			try {
				while (cursor.hasNext()) {
					newFriends=cursor.next();
					 toUserId =Integer.valueOf(newFriends.getString("toUserId"));
					 friends=getFriends(Integer.valueOf(newFriends.getString("userId")),toUserId);
					 newFriends.put("toNickname", getUserManager().getNickName(toUserId));
					if(null!=friends)
						newFriends.put("status", friends.getStatus());
					result.add(newFriends);
				}
			} finally {
				if(null!=cursor)
					cursor.close();
			}
			long count=collection.count(query);
			return new PageVO(result,count, pageIndex, pageSize);
		}
	
	/* 消息免打扰、阅后即焚、聊天置顶相关修改
	 * type = 0  消息免打扰 ,type = 1  阅后即焚 ,type = 2  聊天置顶
	 */
	@Override

	public Friends updateOfflineNoPushMsg(int userId, int toUserId, int offlineNoPushMsg ,int type) {

		/**
		 * 分库分表下的friends 数据更新
		 */
		FindOneAndUpdateOptions options = new FindOneAndUpdateOptions();
		options.returnDocument(ReturnDocument.AFTER);

		Document value = null;
		DBObject dbObject=null;
		Friends rFriends=null;
		switch (type) {
		case 0:
			value = new Document("offlineNoPushMsg", offlineNoPushMsg);
			break;
		case 1:
			value = new Document("isOpenSnapchat", offlineNoPushMsg);
			break;
		case 2:
			value = new Document("openTopChatTime", offlineNoPushMsg);
			break;
		default:
			break;
		}
		if(null==value) {
			return null;
		}
		dbObject = getDBObjectCollection(userId).findOneAndUpdate(new Document("userId",userId).append("toUserId", toUserId), new Document(MongoOperator.SET,value), options);
		// 多点登录下消息免打扰xmpp通知
		if(getUserManager().isOpenMultipleDevices(userId))
			getUserManager().multipointLoginUpdateUserInfo(userId, getUserManager().getNickName(userId), toUserId,getUserManager().getNickName(toUserId),1);

		try {
			  rFriends = DocumentToJavaBean.dbObject2Bean(dbObject, new Friends());
			 System.out.println("new Friends ====== > "+JSONObject.toJSONString(rFriends));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return rFriends;
	}
	
	
	/**
	 * 添加好友统计      时间单位每日，最好可选择：每日、每月、每分钟、每小时
	 * @param startDate
	 * @param endDate
	 * @param timeUnit  统计类型   1: 每个月的数据      2:每天的数据       3.每小时数据   4.每分钟的数据 (小时)
	 */
	public List<Object> getAddFriendsCount(String startDate, String endDate, short timeUnit){
		
		List<Object> countData = new ArrayList<>();

		long startTime = 0; //开始时间（秒）

		long endTime = 0; //结束时间（秒）,默认为当前时间

		/**
		 * 如时间单位为月和天，默认开始时间为当前时间的一年前 ; 时间单位为小时，默认开始时间为当前时间的一个月前;
		 * 时间单位为分钟，则默认开始时间为当前这一天的0点
		 */
		long defStartTime = timeUnit==4? DateUtil.getTodayMorning().getTime()/1000
				: timeUnit==3 ? DateUtil.getLastMonth().getTime()/1000 : DateUtil.getLastYear().getTime()/1000;

		startTime = StringUtil.isEmpty(startDate) ? defStartTime :DateUtil.toDate(startDate).getTime()/1000;
		endTime = StringUtil.isEmpty(endDate) ? DateUtil.currentTimeSeconds() : DateUtil.toDate(endDate).getTime()/1000;

		BasicDBObject queryTime = new BasicDBObject("$ne",null);

		if(startTime!=0 && endTime!=0){
			queryTime.append("$gt", startTime);
			queryTime.append("$lt", endTime);
		}

		BasicDBObject query = new BasicDBObject("createTime",queryTime);
		DB db = SKBeanUtils.getLocalSpringBeanManager().getMongoClient().getDB(getCollectionName());
		//获得用户集合对象
		List<String> collectionList = getCollectionList();
		Map<String,Double> map = new HashMap<String,Double>();

		String mapStr = "function Map() { "
				+ "var date = new Date(this.createTime*1000);"
				+  "var year = date.getFullYear();"
				+  "var month = (\"0\" + (date.getMonth()+1)).slice(-2);"  //month 从0开始，此处要加1
				+  "var day = (\"0\" + date.getDate()).slice(-2);"
				+  "var hour = (\"0\" + date.getHours()).slice(-2);"
				+  "var minute = (\"0\" + date.getMinutes()).slice(-2);"
				+  "var dateStr = date.getFullYear()"+"+'-'+"+"(parseInt(date.getMonth())+1)"+"+'-'+"+"date.getDate();";

		if(timeUnit==1){ // counType=1: 每个月的数据
			mapStr += "var key= year + '-'+ month;";
		}else if(timeUnit==2){ // counType=2:每天的数据
			mapStr += "var key= year + '-'+ month + '-' + day;";
		}else if(timeUnit==3){ //counType=3 :每小时数据
			mapStr += "var key= year + '-'+ month + '-' + day + '  ' + hour +' : 00';";
		}else if(timeUnit==4){ //counType=4 :每分钟的数据
			mapStr += "var key= year + '-'+ month + '-' + day + '  ' + hour + ':'+ minute;";
		}

		mapStr += "emit(key,1);}";

		String reduce = "function Reduce(key, values) {" +
				"return Array.sum(values);" +
				"}";
		for(String str : collectionList){
			DBCollection collection = db.getCollection(str);

			MapReduceCommand.OutputType type =  MapReduceCommand.OutputType.INLINE;//
			MapReduceCommand command = new MapReduceCommand(collection, mapStr, reduce,null, type,query);


			MapReduceOutput mapReduceOutput = collection.mapReduce(command);
			Iterable<DBObject> results = mapReduceOutput.results();

			Double value=null;
			String id=null;
			for (Iterator iterator = results.iterator(); iterator.hasNext();) {
				DBObject obj = (DBObject) iterator.next();
				id=(String)obj.get("_id");
				value= (Double)obj.get("value");
				if(null!=map.get(id)) {
					map.put(id,map.get(id)+value);
				}else {
					map.put(id,value);
				}
			}
		}
		countData=map.entrySet().stream().collect(Collectors.toList());
		map.clear();


		return countData;
	}

	
	// 好友之间的聊天记录
	public PageResult<Document> chardRecord(Integer sender, Integer receiver, Integer page, Integer limit){
		MongoDatabase database = SKBeanUtils.getTigaseManager().getChatMsgDB();
		MongoCollection<Document> collection = getMongoCollection(database, sender);
		Document query = new Document();
		List<Document> queryOr = new ArrayList<Document>();
		if(0 != sender){
			queryOr.add(new Document("sender",sender.toString()).append("receiver", receiver.toString()).append("direction", 0));
		}
		if(0 != receiver){
			queryOr.add(new Document("sender",receiver.toString()).append("receiver", sender.toString()).append("direction", 0));
		}
		query.append(MongoOperator.OR, queryOr);	
		
		long total = collection.count(query);
		List<Document> pageData = Lists.newArrayList();


		  MongoCursor<Document> iterator = collection.find(query).sort(new Document("_id", -1)).skip((page-1) * limit).limit(limit).iterator();
		
		PageResult<Document> result=new PageResult<Document>();
		try {
			while (iterator.hasNext()) {
				Document dbObj =  iterator.next();
				JSONObject body = JSONObject.parseObject(dbObj.getString("message"));
				if(null != body.getBoolean("isEncrypt") && true ==body.getBoolean("isEncrypt")){
					dbObj.put("isEncrypt", 1);
				}else{
					dbObj.put("isEncrypt", 0);
				}
				try {
					dbObj.put("sender_nickname", getUserManager().getNickName(Integer.valueOf(dbObj.getString("sender"))));
				} catch (Exception e) {
					dbObj.put("sender_nickname", "未知");
				}
				try {
					dbObj.put("receiver_nickname", getUserManager().getNickName(Integer.valueOf(dbObj.getString("receiver"))));
				} catch (Exception e) {
					dbObj.put("receiver_nickname", "未知");
				}
				try {
					dbObj.put("content",
							dbObj.get("content"));
				} catch (Exception e) {
					dbObj.put("content", "--");
				}
				pageData.add(dbObj);
			}
		} finally {
			if(null!=iterator)
				iterator.close();
		}


		result.setData(pageData);
		result.setCount(total);
		return result;
	}
	
	/** @Description:（删除好友间的聊天记录） 
	**/
	public void delFriendsChatRecord(int sender,String... messageIds){
		MongoDatabase database = SKBeanUtils.getTigaseManager().getChatMsgDB();
		MongoCollection<Document> dbCollection = SKBeanUtils.getTigaseManager().getMongoCollection(database,sender);
		for(String messageId : messageIds){
			Document query = new Document();
			query.put("messageId", messageId);
			dbCollection.deleteMany(query);
		}
	}

	/** @Description: 导出好友列表 
	* @param userId
	* @param request
	* @param response
	* @return
	**/ 
	public Workbook exprotExcelFriends(Integer userId,HttpServletRequest request,HttpServletResponse response) {

		String name = getUserManager().getNickName(userId)+"的好友明细";

		String fileName ="friends.xlsx";

		List<Friends> friends;
		
		List<Friends> friendsList = SKBeanUtils.getRedisService().getFriendsList(userId);
		if (null != friendsList && friendsList.size() > 0) {
			friends = friendsList;
		} else {
			friends = SKBeanUtils.getFriendsRepository().allFriendsInfo(userId);
		}
		List<String> titles = Lists.newArrayList();
		titles.add("toUserId");
		titles.add("toNickname");
		titles.add("remarkName");
		titles.add("telephone");
		titles.add("status");
		titles.add("blacklist");
		titles.add("isBeenBlack");
		titles.add("offlineNoPushMsg");
		titles.add("createTime");

		List<Map<String, Object>> values = Lists.newArrayList();

		for (Friends friend : friends) {
			// 过滤系统10000号不返回
			if(10000 == friend.getToUserId())
				continue;
			Map<String, Object> map = Maps.newConcurrentMap();
			map.put("toUserId", friend.getToUserId());
			map.put("toNickname", friend.getToNickname());
			map.put("telephone", getUserManager().getUser(friend.getToUserId()).getPhone());
			map.put("status", friend.getStatus() == -1?"黑名单":friend.getStatus() == 2 ? "好友" : "关注");
			map.put("blacklist", friend.getBlacklist() == 1 ?"是":"否");
			map.put("isBeenBlack", friend.getIsBeenBlack() == 1 ?"是":"否");
			map.put("offlineNoPushMsg", friend.getBlacklist() == 1 ?"是":"否");
			map.put("createTime", DateUtil.strToDateTime(friend.getCreateTime()));
			values.add(map);
		}

		Workbook workBook = ExcelUtil.generateWorkbook(name, "xlsx", titles, values);
		response.reset();
		try {
			response.setHeader("Content-Disposition",
					"attachment;filename=" + new String(fileName.getBytes(), "utf-8"));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return workBook;
	}
	

	/** @Description:校验是否为好友或通讯录好友
	* @param userId
	* @param toUserId
	* @param type  -1 所有人不显示 1所有人显示  2 所有好友显示   3 手机联系人显示
	* @return
	**/
	public boolean isAddressBookOrFriends(Integer userId,Integer toUserId,int type){
		boolean flag = false;
		switch (type) {
		case -1:
			break;
		case 1:
			flag = !flag;
			break;
		case 2:
			List<Integer> friendsUserIdsList;
			List<Integer> allFriendsUserIdsList = SKBeanUtils.getRedisService().getFriendsUserIdsList(userId);
			if(null != allFriendsUserIdsList && allFriendsUserIdsList.size() > 0)
				friendsUserIdsList = allFriendsUserIdsList;
			else{
				List<Integer> friendsUserIdsDB = SKBeanUtils.getFriendsManager().queryFansId(userId);
				friendsUserIdsList = friendsUserIdsDB;
				SKBeanUtils.getRedisService().saveFriendsUserIdsList(userId, friendsUserIdsList);
			}
			flag = friendsUserIdsList.contains(toUserId);
			break;
		case 3:
			List<Integer> addressBookUserIdsList;
			List<Integer> allAddressBookUserIdsList = SKBeanUtils.getRedisService().getAddressBookFriendsUserIds(userId);
			if(null != allAddressBookUserIdsList && allAddressBookUserIdsList.size() > 0)
				addressBookUserIdsList = allAddressBookUserIdsList;
			else{
				List<Integer> AddressBookUserIdsDB = SKBeanUtils.getAddressBookManger().getAddressBookUserIds(userId);
				addressBookUserIdsList = AddressBookUserIdsDB;
				SKBeanUtils.getRedisService().saveAddressBookFriendsUserIds(userId, addressBookUserIdsList);
			}
			flag = addressBookUserIdsList.contains(toUserId);
			break;
		default:
			break;
		}
		return flag;
	}

	public void updateToFriendUserType(int toUserId,int userType,List<Integer> roles){
		getFriendsRepository().updateToFriendUserType(toUserId,userType,roles);
	}

	/**
	 * 修改和某个好友的消息加密方式
	 * @param friendsUserId
	 * @return
	 */
	public void  modifyEncryptType(int userId,int toUserId,byte type) {
		SKBeanUtils.getFriendsRepository().updateFriendsEncryptType(userId, toUserId, type);
		SKBeanUtils.getRedisService().deleteFriends(userId);
	}
}
